//
//  LLRouter.m
//  LLFoundation
//
//  Created by my_liu on 2016/11/14.
//  Copyright © 2016年 . All rights reserved.
//

#import "LLRouter.h"
#import <objc/runtime.h>
#import "JSObjection.h"

#define LLRouterException @"LLRouterException"

@implementation LLRouterOptions

@end

@interface LLRouter ()

@property (strong, nonatomic) NSMutableDictionary *routes;

@end

@implementation LLRouter

+ (instancetype)shareInstance
{
    static LLRouter *router = nil;
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        if (!router) {
            router = [[self alloc] init];
        }
    });
    return router;
    
}

- (id)init
{
    
    self = [super init];
    
    if(self){
        
        _routes = [NSMutableDictionary dictionary];
        
    }
    
    return self;
}

- (NSString *)createOpenUrlWithRoute:(NSString *)route transitionStyle:(LLUITransitionStyle)style openParams:(NSArray *)openParams
{
    if(!route||[route length]==0){
        
        return nil;
    }
    
    NSMutableString * url = [NSMutableString stringWithFormat:@"%@?",route];
    
    [url appendFormat:@"%@=%ld&",kLLUITransitionStyle,(long)style];
    
    [openParams enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        
        [url appendFormat:@"argument%lu=%@&",(unsigned long)idx,obj];
        
    }];
    return [url substringToIndex:url.length - 1];
}

- (void)map:(NSString *)route toProtocol:(id)protocol
{
    LLRouterOptions * options = [[LLRouterOptions alloc] init];
    
    options.protocol = protocol;
    
    [_routes setObject:options forKey:route];
}

- (LLRouterOptions *)parseOpenUrl:(NSString *)openUrl
{
    
    
    NSMutableArray * openParams = [NSMutableArray  array];
    
    
    NSString * route;
    
    NSRange  routeRange = [openUrl rangeOfString:@"?"];
    
    if(routeRange.location != NSNotFound){
        
        route = [openUrl substringToIndex:routeRange.location];
    }else{
        
        route = openUrl;
    }
    
    
    
    LLRouterOptions * option = self.routes[route];
    
    LLRouterOptions * routerOptions ;
    
    if(option){
        
        routerOptions = [[LLRouterOptions alloc] init];
        
        routerOptions.openClass = option.openClass;
        
        routerOptions.protocol = option.protocol;
        
        if(routeRange.location != NSNotFound){
            
            NSString * paramString = [openUrl substringFromIndex:[openUrl rangeOfString:@"?"].location + 1];
            
            NSArray * params = [paramString componentsSeparatedByString:@"&"];
            
            [params enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                
                NSString * string = (NSString *)obj;
                
                NSArray * subStrs = [string componentsSeparatedByString:@"="];
                
                if(subStrs.count >1){
                    
                    if([subStrs[0] isEqualToString:kLLUITransitionStyle]){
                        
                        routerOptions.transitionStyle = [subStrs[1] intValue];
                        
                    }else{
                        
                        [openParams addObject:subStrs[1]];
                    }
                }
            }];
            routerOptions.openParams = [NSArray arrayWithArray:openParams];
        }
    }
    return routerOptions;
}

- (id)bulidObjectWithInitializer:(SEL)initializer class:(Class)class arguments:(NSArray *)arguments
{
    NSMethodSignature *signature = [class methodSignatureForSelector:initializer];//获得类方法签名
    __autoreleasing id instance = nil;
    BOOL isClassMethod = signature != nil && initializer != @selector(init);
    
    if (!isClassMethod) {
        instance = [class alloc];
        signature = [class instanceMethodSignatureForSelector:initializer];//获得实例方法签名
    }
    
    if (signature) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        [invocation setTarget:isClassMethod ? class : instance];
        [invocation setSelector:initializer];
        for (int i = 0; i < arguments.count; i++) {
            __unsafe_unretained id argument = [arguments objectAtIndex:i];
            [invocation setArgument:&argument atIndex:i + 2];
        }
        [invocation invoke];
        [invocation getReturnValue:&instance];//获得返回值，实例
        return instance;
    } else {
        @throw [NSException exceptionWithName:LLRouterException reason:[NSString stringWithFormat:@"Could not find initializer '%@' on %@", NSStringFromSelector(initializer), NSStringFromClass(class)] userInfo:nil];
    }
    return nil;
    
    
}

- (void)open:(NSString *)url withCurrentNavigationcontroller:(UINavigationController *)navigationController animated:(BOOL)animated
{
    
    if(!navigationController){
        
        return;
    }
    
    NSRange routeHeaderRange = [url rangeOfString:@"://"];
    
    __block NSString * routeHeader;
    
    if(routeHeaderRange.location != NSNotFound){
        
        routeHeaderRange = NSMakeRange(0, routeHeaderRange.location + routeHeaderRange.length);
        
        routeHeader = [url substringWithRange:routeHeaderRange];
        
    }
    
    
    NSArray * openUrls = [url componentsSeparatedByString:@"@"];
    
    if(routeHeader){
        
        openUrls = [[url substringFromIndex:routeHeaderRange.location + routeHeaderRange.length] componentsSeparatedByString:@"@"];
    }
    
    __weak LLRouter * weakSelf = self;
    
    __block NSMutableArray * viewcontrollers = [NSMutableArray arrayWithArray:navigationController.viewControllers];
    
    __block NSMutableArray * navigationControllers = [NSMutableArray arrayWithObject:navigationController];
    
    __block NSMutableDictionary * navigationSubviewControllerDict = [NSMutableDictionary dictionaryWithObject:viewcontrollers forKey:[NSString stringWithFormat:@"%lu",(unsigned long)navigationController.hash]];
    
    [openUrls enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        
        NSString * openUrl = (NSString *)obj;
        
        if(routeHeader){
            
            openUrl = [NSString stringWithFormat:@"%@%@",routeHeader,obj];
            
        }
        
        LLRouterOptions * routerOptions =  [weakSelf parseOpenUrl:openUrl];
        
        LLUITransitionStyle style = routerOptions.transitionStyle;
        
        UIViewController *viewController = [[JSObjection defaultInjector] getObject:routerOptions.protocol argumentList:routerOptions.openParams];
        
        if(style == LLUITransitionStyleAutoReuse){
            
            __block  NSInteger popIndex = -1;
            
            [viewcontrollers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                
                if([obj isKindOfClass:[viewController class]]){
                    
                    popIndex = idx;
                    
                    *stop = YES;
                }
                
            }];
            
            if(popIndex >=0){
                
                
                [viewcontrollers removeObjectsInRange:NSMakeRange(popIndex + 1,viewcontrollers.count - popIndex - 1)];
            }
            
            
        }else if(style == LLUITransitionStylePush){
            
            
            if(viewController){
                
                [viewcontrollers addObject:viewController];
            }
            
            
        }else if(style == LLUITransitionStylePresent){
            
            UINavigationController * openNavigationController = [[UINavigationController  alloc] initWithRootViewController:viewController];
            
            [navigationControllers addObject:openNavigationController];
            
            viewcontrollers = [NSMutableArray arrayWithArray:openNavigationController.viewControllers];
            
            [navigationSubviewControllerDict setObject:viewcontrollers forKey:[NSString stringWithFormat:@"%lu",(unsigned long)openNavigationController.hash]];
        }else if(style == LLUITransitionStyleAutoReusePush){
            
            __block NSInteger reuseIndex = -1;
            
            [viewcontrollers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                
                
                if([obj isKindOfClass:[viewController class]]){
                    
                    reuseIndex = idx;
                    
                    *stop = YES;
                    
                }
                
                
            }];
            
            if(reuseIndex >= 0){
                
                [viewcontrollers removeObjectsInRange:NSMakeRange(reuseIndex + 1, viewcontrollers.count - reuseIndex - 1)];
            }else{
                
                
                if(viewController){
                    
                    [viewcontrollers addObject:viewController];
                }
                
            }
            
            
        }
        
    }];
    
    
    [navigationControllers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        
        UINavigationController * nav = (UINavigationController *)obj;
        
        NSMutableArray * controllers = navigationSubviewControllerDict[[NSString stringWithFormat:@"%lu",(unsigned long)nav.hash]];
        
        if(nav == navigationController){
            
            if(idx + 1 == navigationControllers.count){
                
                [nav setViewControllers:controllers animated:animated];
            }else{
                
                [nav setViewControllers:controllers];
            }
            
        }else{
            
            UINavigationController * lastNav = [navigationControllers objectAtIndex:idx - 1];
            
            [nav setViewControllers:controllers];
            
            if(idx + 1 == navigationControllers.count){
                
                [lastNav presentViewController:nav animated:animated completion:^{
                    
                }];
                
            }else{
                
                [lastNav presentViewController:nav animated:NO completion:^{
                    
                }];
            }
        }
    }];
}

- (void)popWithCurrentNavigationcontroller:(UINavigationController *)navigationController animated:(BOOL)animated
{
    
    NSInteger currentIndex = [navigationController.viewControllers indexOfObject:navigationController.visibleViewController];
    
    if(currentIndex > 0){
        
        [navigationController popViewControllerAnimated:animated];
        
    }else if(currentIndex == 0){
        
        [navigationController dismissViewControllerAnimated:animated completion:nil];
    }
}

@end
